package eu.webhib.webblog.gui.controller;

import eu.webhib.frmwrk.jsf.base.EditBaseController;
import eu.webhib.frmwrk.jsf.utils.JsfUtil;
import eu.webhib.webblog.application.ApplMail;
import eu.webhib.webblog.gui.application.GuiApplication;
import eu.webhib.webblog.gui.application.SessionMoveIntf;
import eu.webhib.webblog.domain.User;
import eu.webhib.webblog.service.factory.ServiceFactory;
import eu.webhib.webblog.service.intf.UserService;
import javax.faces.bean.*;
import javax.faces.event.*;
import org.apache.log4j.Logger;

/**
 * Controller of the User Password Reset Confirm page
 */
@ManagedBean(name = "pwresconf")
@SessionScoped
public class PasswordResetConfirm extends EditBaseController implements SessionMoveIntf {

   private static final Logger log = Logger.getLogger(PasswordResetConfirm.class);
   private static UserService userService = ServiceFactory.getUserService();
   // User input data
   private String userName;
   private String passWord;
   private String passWordConfirm;
   // password reset was confirmed for this user, but still has to complete the password reset
   private Long confirmedUserId = null;
   private boolean passwordResetConfirmed = false;

   //
   // User input  ----------------------------------------------------------
   //
   public String getUserName() {
      return userName;
   }

   public void setUserName(String userName) {
      this.userName = userName;
   }

   public String getPassWord() {
      return "";
   }

   public void setPassWord(String passWord) {
      this.passWord = passWord;
   }

   public String getPassWordConfirm() {
      return "";
   }

   public void setPassWordConfirm(String passWordConfirm) {
      this.passWordConfirm = passWordConfirm;
   }

   public boolean isPasswordResetConfirmed() {
      return passwordResetConfirmed;
   }

   //
   // Password Reset confirmation -----------------------------------
   //
   public void passwordResetConfirmListener(ComponentSystemEvent event) {
      log.info("passwordResetConfirmListener");
      new EditListenerClosure() {

         @Override
         protected void run(ComponentSystemEvent event) {
            doPasswordResetConfirmListener();
         }
      }.start(event);
   }

   private void doPasswordResetConfirmListener() {
      if (GuiApplication.isAuthenticated()) {
         JsfUtil.sendRedirect(GuiApplication.getNotAtLoggedInStatePageURI());
         return;
      }
      // only if reset password confirmation link is applied, not at post back
      if (JsfUtil.isGet()) {
         passwordResetConfirmed = checkPasswordResetConfirm();
         if (passwordResetConfirmed) {
            setInfoMessage("info_passwordresetconfirm_ok");
         } else {
            setErrorMessage("error_passwordresetconfirm");
         }
      }
   }

   private boolean checkPasswordResetConfirm() {
      String confirmSecret = JsfUtil.getRequestParam(ApplMail.emailConfirmUrlParam);
      log.debug("confirmSecret: " + confirmSecret);
      if (confirmSecret == null) {
         return false;
      }
      // lookup user by confirmation secret
      User user = userService.findByAttributeSingle("confirmSecret", confirmSecret);
      if (user == null) {
         log.warn("no user found for confirmSecret");
         return false;
      }
      // check password rest confirmation for this user
      if (!user.checkPasswordResetConfirm()) {
         log.warn("user not in right status");
         return false;
      }
      // Password reset now succesfully confirmed by the user
      // we are in a senistive pre loggedin state, since user is allowed to change the password
      GuiApplication.moveToNewSession();
      // rember the user id in the session for the password reset complete action
      confirmedUserId = user.getId();
      return true;
   }

   // User is to complete the password reset:
   // has entered username, new password and confirmation password
   public String passwordResetCompleteAction() {
      log.info("passwordResetCompleteAction");
      return new EditActionClosure() {

         @Override
         protected void run() {
            doPasswordResetCompleteAction();
         }
      }.start();
   }

   private boolean doPasswordResetCompleteAction() {
      // check if session was not expired
      if (confirmedUserId == null) {
         setErrorMessage("error_passwordresetcomplete_session");
         return false;
      }
      // check if user is still in database
      User user = userService.findId(confirmedUserId);
      if (user == null) {
         setErrorMessage("error_passwordresetcomplete_userstate");
         return false;
      }
      // check if user is still in the right state
      if (!user.checkPasswordResetConfirm()) {
         setErrorMessage("error_passwordresetcomplete_userstate");
         return false;
      }

      // check input data fields: user has to know the userName
      if (!this.userName.equals(user.getUserName())) {
         setFieldError("username", "error_passwordresetcomplete_username");
      }
      // passwords checked against same requirements as for user registration
      Register.checkPasswords(this.passWord, this.passWordConfirm);
      // if there was an input data error: user try again
      if (!isInputOk()) {
         return false;
      }

      // set the password in the user object, change state and save to database
      user.passwordResetComplete(this.passWord);
      userService.save(user);

      // set user to logged in state
      GuiApplication.getAuthenticationData().setAuthenticatedUser(user);
      passwordResetConfirmed = false;
      confirmedUserId = null;
      passWord = null;
      passWordConfirm = null;
      userName = null;

      // continue
      JsfUtil.sendRedirect(GuiApplication.getHistroyPageURI());
      return true;
   }

   // Password reset confirmation was not successful, user quits this information
   public String passwordResetConfirmedErrorAction() {
      JsfUtil.sendRedirect(GuiApplication.getHistroyPageURI());
      return null;
   }
}
